// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef MEDIA_BASE_AUDIO_BUFFER_QUEUE_H_
#define MEDIA_BASE_AUDIO_BUFFER_QUEUE_H_

#include <deque>

#include "base/macros.h"
#include "media/base/audio_buffer.h"
#include "media/base/media_export.h"

namespace media {

class AudioBus;

// A queue of AudioBuffers to support reading of arbitrary chunks of a media
// data source. Audio data can be copied into an AudioBus for output. The
// current position can be forwarded to anywhere in the buffered data.
//
// This class is not inherently thread-safe. Concurrent access must be
// externally serialized.
class MEDIA_EXPORT AudioBufferQueue {
public:
    AudioBufferQueue();
    ~AudioBufferQueue();

    // Clears the buffer queue.
    void Clear();

    // Appends |buffer_in| to this queue.
    void Append(const scoped_refptr<AudioBuffer>& buffer_in);

    // Reads a maximum of |frames| frames into |dest| from the current position.
    // Returns the number of frames read. The current position will advance by the
    // amount of frames read. |dest_frame_offset| specifies a starting offset into
    // |dest|. On each call, the frames are converted from their source format
    // into the destination AudioBus.
    int ReadFrames(int frames, int dest_frame_offset, AudioBus* dest);

    // Copies up to |frames| frames from current position to |dest|. Returns
    // number of frames copied. Doesn't advance current position. Starts at
    // |source_frame_offset| from current position. |dest_frame_offset| specifies
    // a starting offset into |dest|. On each call, the frames are converted from
    // their source format into the destination AudioBus.
    int PeekFrames(int frames,
        int source_frame_offset,
        int dest_frame_offset,
        AudioBus* dest);

    // Moves the current position forward by |frames| frames. If |frames| exceeds
    // frames available, the seek operation will fail.
    void SeekFrames(int frames);

    // Returns the number of frames buffered beyond the current position.
    int frames() const { return frames_; }

private:
    // Definition of the buffer queue.
    typedef std::deque<scoped_refptr<AudioBuffer>> BufferQueue;

    // An internal method shared by ReadFrames() and SeekFrames() that actually
    // does reading. It reads a maximum of |frames| frames into |dest|. Returns
    // the number of frames read. The current position will be moved forward by
    // the number of frames read if |advance_position| is set. If |dest| is NULL,
    // only the current position will advance but no data will be copied.
    // |source_frame_offset| can be used to skip frames before reading.
    // |dest_frame_offset| specifies a starting offset into |dest|.
    int InternalRead(int frames,
        bool advance_position,
        int source_frame_offset,
        int dest_frame_offset,
        AudioBus* dest);

    BufferQueue::iterator current_buffer_;
    BufferQueue buffers_;
    int current_buffer_offset_;

    // Number of frames available to be read in the buffer.
    int frames_;

    DISALLOW_COPY_AND_ASSIGN(AudioBufferQueue);
};

} // namespace media

#endif // MEDIA_BASE_AUDIO_BUFFER_QUEUE_H_
